{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 如何在聊天模型中使用few-shotting示例\n",
    "\n",
    "- 本指南介绍了如何使用示例输入和输出提示聊天模型。为模型提供一些这样的示例称为few-shotting，这是一种简单而强大的方法来指导生成，在某些情况下可以大大提高模型性能。\n",
    "- “few-shotting”常见于机器学习领域，指的是在训练模型时，只使用少量的有标注数据进行学习和训练的方法。这种方法与传统的需要大量数据进行训练的方式有所不同，旨在通过有限的示例让模型获得一定的泛化能力和预测能力。\n",
    "- few-shotting提示模板的目标是根据输入动态选择示例，然后在最终提示中格式化示例以提供模型。\n",
    "- 对于如何最好地进行few-shotting提示似乎没有可靠的共识，最佳提示编译可能会因模型而异。因此，langchain提供了像FewShotChatMessagePromptTemplate这样的few-shotting提示模板作为一个灵活的起点，你可以根据需要修改或替换它们。\n",
    "\n",
    "#### 有时，您可能只想根据输入从整个集合中选择几个示例来显示。为此，您可以将传递给FewShotChatMessagePromptTemplate的examples替换为example_selector。其他组件与上述相同！我们的动态少镜头提示模板如下所示："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Note: you may need to restart the kernel to use updated packages.\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "[notice] A new release of pip is available: 23.1.2 -> 24.1.2\n",
      "[notice] To update, run: python.exe -m pip install --upgrade pip\n"
     ]
    }
   ],
   "source": [
    "%pip install -qU langchain langchain_openai langchain_chroma"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 让我们浏览一个带有SemanticSimilarityExampleSelector的示例。由于此实现使用向量存储来根据语义相似性选择示例，因此我们希望首先填充存储。由于这里的基本思想是我们希望搜索并返回与文本输入最相似的示例，因此我们嵌入了提示示例的values，而不是考虑键："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['2 🦜 2 4', '2 🦜 3 5', '2 🦜 4 6', 'What did the cow say to the moon? nothing at all', 'Write me a poem about the moon One for the moon, and one for me, who are we to talk about the moon?']\n"
     ]
    }
   ],
   "source": [
    "from langchain_chroma import Chroma\n",
    "from langchain_core.example_selectors import SemanticSimilarityExampleSelector\n",
    "from langchain_openai import OpenAIEmbeddings\n",
    "\n",
    "examples = [\n",
    "    {\"input\": \"2 🦜 2\", \"output\": \"4\"},\n",
    "    {\"input\": \"2 🦜 3\", \"output\": \"5\"},\n",
    "    {\"input\": \"2 🦜 4\", \"output\": \"6\"},\n",
    "    {\"input\": \"What did the cow say to the moon?\", \"output\": \"nothing at all\"},\n",
    "    {\n",
    "        \"input\": \"Write me a poem about the moon\",\n",
    "        \"output\": \"One for the moon, and one for me, who are we to talk about the moon?\",\n",
    "    },\n",
    "]\n",
    "\n",
    "to_vectorize = [\" \".join(example.values()) for example in examples]\n",
    "print(to_vectorize)\n",
    "embeddings = OpenAIEmbeddings()\n",
    "vectorstore = Chroma.from_texts(to_vectorize, embeddings, metadatas=examples)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 创建向量存储后，我们可以创建example_selector。在这里，我们将单独调用它，并在其上设置k以仅获取最接近输入的两个示例。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'input': 'What did the cow say to the moon?', 'output': 'nothing at all'},\n",
       " {'input': '2 🦜 4', 'output': '6'}]"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "example_selector = SemanticSimilarityExampleSelector(\n",
    "    vectorstore=vectorstore,\n",
    "    k=2,\n",
    ")\n",
    "\n",
    "# The prompt template will load examples by passing the input do the `select_examples` method\n",
    "example_selector.select_examples({\"input\": \"horse\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 我们现在使用上面创建的example_selector组装提示模板。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[HumanMessage(content='2 🦜 3'), AIMessage(content='5'), HumanMessage(content='2 🦜 4'), AIMessage(content='6')]\n"
     ]
    }
   ],
   "source": [
    "from langchain_core.prompts import ChatPromptTemplate, FewShotChatMessagePromptTemplate\n",
    "\n",
    "# Define the few-shot prompt.\n",
    "few_shot_prompt = FewShotChatMessagePromptTemplate(\n",
    "    # The input variables select the values to pass to the example_selector\n",
    "    input_variables=[\"input\"],\n",
    "    example_selector=example_selector,\n",
    "    # Define how each example will be formatted.\n",
    "    # In this case, each example will become 2 messages:\n",
    "    # 1 human, and 1 AI\n",
    "    example_prompt=ChatPromptTemplate.from_messages(\n",
    "        [(\"human\", \"{input}\"), (\"ai\", \"{output}\")]\n",
    "    ),\n",
    ")\n",
    "\n",
    "print(few_shot_prompt.invoke(input=\"What's 3 🦜 3?\").to_messages())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 并且我们可以将这个few_shot的聊天消息提示模板传递到另一个聊天提示模板中："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "messages=[SystemMessage(content='You are a wondrous wizard of math.'), HumanMessage(content='2 🦜 3'), AIMessage(content='5'), HumanMessage(content='2 🦜 4'), AIMessage(content='6'), HumanMessage(content=\"What's 3 🦜 3?\")]\n"
     ]
    }
   ],
   "source": [
    "final_prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\"system\", \"You are a wondrous wizard of math.\"),\n",
    "        few_shot_prompt,\n",
    "        (\"human\", \"{input}\"),\n",
    "    ]\n",
    ")\n",
    "\n",
    "print(final_prompt.invoke(input=\"What's 3 🦜 3?\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 最后，您可以将模型连接到few_shot提示上。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'6'"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_core.output_parsers import StrOutputParser\n",
    "\n",
    "llm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0.0)\n",
    "\n",
    "chain = final_prompt | llm | StrOutputParser()\n",
    "\n",
    "chain.invoke({\"input\": \"What's 3 🦜 3?\"})"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
